import { error } from "@sveltejs/kit";
import { logger } from "$lib/server/logger.js";
import { fetch } from "undici";
import { isValidUrl } from "$lib/server/urlSafety";

const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const FETCH_TIMEOUT = 30000; // 30 seconds
const SECURITY_HEADERS: HeadersInit = {
	// Prevent any active content from executing if someone navigates directly to this endpoint.
	"Content-Security-Policy":
		"default-src 'none'; frame-ancestors 'none'; sandbox; script-src 'none'; img-src 'none'; style-src 'none'; connect-src 'none'; media-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'",
	"X-Content-Type-Options": "nosniff",
	"X-Frame-Options": "DENY",
	"Referrer-Policy": "no-referrer",
};

export async function GET({ url }) {
	const targetUrl = url.searchParams.get("url");

	if (!targetUrl) {
		logger.warn("Missing 'url' parameter");
		throw error(400, "Missing 'url' parameter");
	}

	if (!isValidUrl(targetUrl)) {
		logger.warn({ targetUrl }, "Invalid or unsafe URL (only HTTPS is supported)");
		throw error(400, "Invalid or unsafe URL (only HTTPS is supported)");
	}

	try {
		// Fetch with timeout
		const controller = new AbortController();
		const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);

		const response = await fetch(targetUrl, {
			signal: controller.signal,
			headers: {
				"User-Agent": "HuggingChat-Attachment-Fetcher/1.0",
			},
		}).finally(() => clearTimeout(timeoutId));

		if (!response.ok) {
			logger.error({ targetUrl, response }, `Error fetching URL. Response not ok.`);
			throw error(response.status, `Failed to fetch: ${response.statusText}`);
		}

		// Check content length if available
		const contentLength = response.headers.get("content-length");
		if (contentLength && parseInt(contentLength) > MAX_FILE_SIZE) {
			throw error(413, "File too large (max 10MB)");
		}

		// Stream the response back
		const originalContentType = response.headers.get("content-type") || "application/octet-stream";
		// Send as text/plain for safety; expose the original type via secondary header
		const safeContentType = "text/plain; charset=utf-8";
		const contentDisposition = response.headers.get("content-disposition");

		const headers: HeadersInit = {
			"Content-Type": safeContentType,
			"X-Forwarded-Content-Type": originalContentType,
			"Cache-Control": "public, max-age=3600",
			...(contentDisposition ? { "Content-Disposition": contentDisposition } : {}),
			...SECURITY_HEADERS,
		};

		// Get the body as array buffer to check size
		const arrayBuffer = await response.arrayBuffer();

		if (arrayBuffer.byteLength > MAX_FILE_SIZE) {
			throw error(413, "File too large (max 10MB)");
		}

		return new Response(arrayBuffer, { headers });
	} catch (err) {
		if (err instanceof Error) {
			if (err.name === "AbortError") {
				logger.error(err, `Request timeout`);
				throw error(504, "Request timeout");
			}

			logger.error(err, `Error fetching URL`);
			throw error(500, `Failed to fetch URL: ${err.message}`);
		}
		logger.error(err, `Error fetching URL`);
		throw error(500, "Failed to fetch URL.");
	}
}
